/**
 * 
 */
package br.edu.ufcg.compiladores.brasigol.semantico;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import br.edu.ufcg.compiladores.brasigol.exceptions.ExclusaoInvalidaException;
import br.edu.ufcg.compiladores.brasigol.exceptions.NoEntryException;
import br.edu.ufcg.compiladores.brasigol.exceptions.RedeclaracaoDeSimboloException;

/**
 * @author Marcelo Emanoel
 * 
 */
public class TabelaDeSimbolos {

	private Map<String, Identificador> tabela;
	private int posicaoDeMemoria;
	private List<Identificador> simbolosDeclarados;
	/**
	 * @return Returns the posicaoDeMemoria.
	 */
	public int getPosicaoDeMemoria() {
		return posicaoDeMemoria;
	}

	/**
	 * @param posicaoDeMemoria The posicaoDeMemoria to set.
	 */
	public void setPosicaoDeMemoria(int posicaoDeMemoria) {
		this.posicaoDeMemoria = posicaoDeMemoria;
	}

	public TabelaDeSimbolos() {
		setTabela(new TreeMap<String, Identificador>());
		setPosicaoDeMemoria(0);
		simbolosDeclarados = new ArrayList<Identificador>();
	}

	public boolean contemSimbolo(String simbolo) {
		return getTabela().containsKey(simbolo);
	}

	public void addEntry(Identificador entrada) throws RedeclaracaoDeSimboloException{
		String chave = entrada.getIdentificador();
		if (contemSimbolo(chave)) {
			throw new RedeclaracaoDeSimboloException(entrada);
		}
		entrada.setPosicaoInicialMemoria(getPosicaoDeMemoria());
		getTabela().put(chave, entrada);
		if(entrada.getTipoDeDado() == null && !entrada.isErro()){
			simbolosDeclarados.add(entrada);
		}
		
	}
	public void removeEntry(Identificador entrada) throws ExclusaoInvalidaException{
		String key = entrada.getIdentificador();
		if (!contemSimbolo(key)) {
			throw new ExclusaoInvalidaException(entrada);
		}
		getTabela().remove(key);
	}
	public Identificador recuperarIdentificador(String key){
		if(!contemSimbolo(key)){
			throw new NoEntryException(key);
		}
		return getTabela().get(key);
	}
	/**
	 * @return the tabela
	 */
	private Map<String, Identificador> getTabela() {
		return tabela;
	}

	/**
	 * @param tabela the tabela to set
	 */
	private void setTabela(Map<String, Identificador> tabela) {
		this.tabela = tabela;
	}
	
	public String toString() {
		return tabela.toString();
	}
	
	public List<Identificador> getIdentificadoresSemTipo(){
		return simbolosDeclarados;
	}

	public List<Identificador> getUltimasVariaveisAtribuidas() {
		return this.simbolosDeclarados;
	}

	public void limpaIdentificadoresSemTipo() {
		this.simbolosDeclarados.clear();
	}
}